<script>
import {
  GlIcon,
  GlLink,
  GlModal,
  GlButton,
  GlModalDirective,
  GlLoadingIcon,
  GlTooltipDirective,
} from '@gitlab/ui';
import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import { s__, __ } from '~/locale';

import { HOW_TO_TRACK_TIME, timeTrackingQueries } from '../../constants';
import eventHub from '../../event_hub';
import TimeTrackingCollapsedState from './collapsed_state.vue';
import TimeTrackingComparisonPane from './comparison_pane.vue';
import TimeTrackingReport from './report.vue';
import TimeTrackingSpentOnlyPane from './spent_only_pane.vue';
import { CREATE_TIMELOG_MODAL_ID } from './constants';
import CreateTimelogForm from './create_timelog_form.vue';

export default {
  name: 'IssuableTimeTracker',
  i18n: {
    noTimeTrackingText: __('No estimate or time spent'),
    estimatedOnlyText: s__('TimeTracking|Estimated:'),
  },
  components: {
    GlIcon,
    GlLink,
    GlModal,
    GlButton,
    GlLoadingIcon,
    TimeTrackingCollapsedState,
    TimeTrackingSpentOnlyPane,
    TimeTrackingComparisonPane,
    TimeTrackingReport,
    CreateTimelogForm,
  },
  directives: {
    GlModal: GlModalDirective,
    GlTooltip: GlTooltipDirective,
  },
  inject: {
    issuableType: {
      default: null,
    },
  },
  props: {
    limitToHours: {
      type: Boolean,
      default: false,
      required: false,
    },
    fullPath: {
      type: String,
      required: false,
      default: '',
    },
    issuableId: {
      type: String,
      required: false,
      default: '',
    },
    issuableIid: {
      type: String,
      required: false,
      default: '',
    },
    initialTimeTracking: {
      type: Object,
      required: false,
      default: null,
    },
    /*
      In issue list, "time-tracking-collapsed-state" is always rendered even if the sidebar isn't collapsed.
      The actual hiding is controlled with css classes:
        Hide "time-tracking-collapsed-state"
          if .right-sidebar .right-sidebar-collapsed .sidebar-collapsed-icon
        Show "time-tracking-collapsed-state"
          if .right-sidebar .right-sidebar-expanded .sidebar-collapsed-icon

      In Swimlanes sidebar, we do not use collapsed state at all.
    */
    showCollapsed: {
      type: Boolean,
      default: true,
      required: false,
    },
    canAddTimeEntries: {
      type: Boolean,
      required: false,
      default: true,
    },
  },
  data() {
    return {
      showHelp: false,
      timeTracking: {
        ...this.initialTimeTracking,
      },
    };
  },
  apollo: {
    issuableTimeTracking: {
      query() {
        return timeTrackingQueries[this.issuableType].query;
      },
      skip() {
        // Skip the query if either of the conditions are true
        // 1. issuableType is not provided
        // 2. Time tracking info was provided via prop
        // 3. issuableIid and fullPath are not provided
        if (!this.issuableType || !timeTrackingQueries[this.issuableType]) {
          return true;
        } else if (this.initialTimeTracking) {
          return true;
        } else if (!this.issuableIid || !this.fullPath) {
          return true;
        }
        return false;
      },
      variables() {
        return {
          iid: this.issuableIid,
          fullPath: this.fullPath,
        };
      },
      update(data) {
        this.timeTracking = {
          ...data.workspace?.issuable,
        };
      },
    },
  },
  computed: {
    isTimeTrackingInfoLoading() {
      return this.$apollo?.queries.issuableTimeTracking?.loading ?? false;
    },
    timeEstimate() {
      return this.timeTracking?.timeEstimate || 0;
    },
    totalTimeSpent() {
      return this.timeTracking?.totalTimeSpent || 0;
    },
    humanTimeEstimate() {
      return this.timeTracking?.humanTimeEstimate || '';
    },
    humanTotalTimeSpent() {
      return this.timeTracking?.humanTotalTimeSpent || '';
    },
    hasTotalTimeSpent() {
      return Boolean(this.totalTimeSpent);
    },
    hasTimeEstimate() {
      return Boolean(this.timeEstimate);
    },
    showComparisonState() {
      return this.hasTimeEstimate && this.hasTotalTimeSpent;
    },
    showEstimateOnlyState() {
      return this.hasTimeEstimate && !this.hasTotalTimeSpent;
    },
    showSpentOnlyState() {
      return this.hasTotalTimeSpent && !this.hasTimeEstimate;
    },
    showNoTimeTrackingState() {
      return !this.hasTimeEstimate && !this.hasTotalTimeSpent;
    },
    showHelpState() {
      return Boolean(this.showHelp);
    },
    isTimeReportSupported() {
      return [TYPE_ISSUE, TYPE_MERGE_REQUEST].includes(this.issuableType) && this.issuableId;
    },
    timeTrackingIconTitle() {
      return this.showHelpState ? '' : HOW_TO_TRACK_TIME;
    },
    timeTrackingIconName() {
      return this.showHelpState ? 'close' : 'question-o';
    },
  },
  watch: {
    /**
     * When `initialTimeTracking` is provided via prop,
     * we don't query the same via GraphQl and instead
     * monitor it for any updates (eg; Epic Swimlanes)
     */
    initialTimeTracking(timeTracking) {
      this.timeTracking = timeTracking;
    },
  },
  created() {
    eventHub.$on('timeTracker:refresh', this.refresh);
  },
  methods: {
    refresh() {
      this.$apollo.queries.issuableTimeTracking.refetch();
    },
    openRegisterTimeSpentModal() {
      this.$root.$emit(BV_SHOW_MODAL, CREATE_TIMELOG_MODAL_ID);
    },
  },
};
</script>

<template>
  <div v-cloak class="time-tracker sidebar-help-wrap" data-testid="time-tracker">
    <time-tracking-collapsed-state
      v-if="showCollapsed"
      :show-comparison-state="showComparisonState"
      :show-no-time-tracking-state="showNoTimeTrackingState"
      :show-help-state="showHelpState"
      :show-spent-only-state="showSpentOnlyState"
      :show-estimate-only-state="showEstimateOnlyState"
      :time-spent-human-readable="humanTotalTimeSpent"
      :time-estimate-human-readable="humanTimeEstimate"
    />
    <div
      class="hide-collapsed gl-line-height-20 gl-text-gray-900 gl-display-flex gl-align-items-center gl-font-weight-bold"
    >
      {{ __('Time tracking') }}
      <gl-loading-icon v-if="isTimeTrackingInfoLoading" size="sm" class="gl-ml-2" inline />
      <gl-button
        v-if="canAddTimeEntries"
        v-gl-tooltip.left
        category="tertiary"
        size="small"
        class="gl-ml-auto"
        data-testid="add-time-entry-button"
        :title="__('Add time entry')"
        @click="openRegisterTimeSpentModal()"
      >
        <gl-icon name="plus" class="gl-text-gray-900!" />
      </gl-button>
    </div>
    <div v-if="!isTimeTrackingInfoLoading" class="hide-collapsed">
      <div v-if="showEstimateOnlyState" data-testid="estimateOnlyPane">
        <span>{{ $options.i18n.estimatedOnlyText }} </span>{{ humanTimeEstimate }}
      </div>
      <time-tracking-spent-only-pane
        v-if="showSpentOnlyState"
        :time-spent-human-readable="humanTotalTimeSpent"
      />
      <div v-if="showNoTimeTrackingState" data-testid="noTrackingPane">
        <span class="gl-text-gray-500">{{ $options.i18n.noTimeTrackingText }}</span>
      </div>
      <time-tracking-comparison-pane
        v-if="showComparisonState"
        :time-estimate="timeEstimate"
        :time-spent="totalTimeSpent"
        :time-spent-human-readable="humanTotalTimeSpent"
        :time-estimate-human-readable="humanTimeEstimate"
        :limit-to-hours="limitToHours"
      />
      <template v-if="isTimeReportSupported">
        <gl-link
          v-if="hasTotalTimeSpent"
          v-gl-modal="'time-tracking-report'"
          data-testid="reportLink"
          href="#"
        >
          {{ __('Time tracking report') }}
        </gl-link>
        <gl-modal
          modal-id="time-tracking-report"
          size="lg"
          :title="__('Time tracking report')"
          :hide-footer="true"
        >
          <time-tracking-report :limit-to-hours="limitToHours" :issuable-id="issuableId" />
        </gl-modal>
      </template>
      <create-timelog-form :issuable-id="issuableId" />
    </div>
  </div>
</template>
